#include "global.h"
#include "keyboard.h"
#include "delay.h"
#include "rs232_interface.h"


#define KEY_L_Pin  GPIO_Pin_6
#define KEY_L_Port GPIOD

#define KEY_R_Pin  GPIO_Pin_9
#define KEY_R_Port GPIOG

#define KEY_C_Pin  GPIO_Pin_10
#define KEY_C_Port GPIOG

#define KEY_U_Pin  GPIO_Pin_11
#define KEY_U_Port GPIOG

#define KEY_D_Pin  GPIO_Pin_12
#define KEY_D_Port GPIOG

static KEY_FIFO_T s_tKey;       /* 按键FIFO变量,结构体 */
static KEY_T s_tBtn[KEY_COUNT];

void InitKeyVar(void);       /* 初始化按键变量 */
void InitKeyHard(void);      /* 初始化按键硬件 */

                             /* 5方向摇杆 */
static uint8_t IsKeyDown_L(void) {
    if (GPIO_ReadInputDataBit(KEY_L_Port, KEY_L_Pin) == Bit_SET) return 1; else return 0;
}
static uint8_t IsKeyDown_R(void) {
    if (GPIO_ReadInputDataBit(KEY_R_Port, KEY_R_Pin) == Bit_SET) return 1; else return 0;
}
static uint8_t IsKeyDown_U(void) {
    if (GPIO_ReadInputDataBit(KEY_U_Port, KEY_U_Pin) == Bit_SET) return 1; else return 0;
}
static uint8_t IsKeyDown_D(void) {
    if (GPIO_ReadInputDataBit(KEY_D_Port, KEY_D_Pin) == Bit_SET) return 1; else return 0;
}
static uint8_t IsKeyDown_C(void) {
    if (GPIO_ReadInputDataBit(KEY_C_Port, KEY_C_Pin) == Bit_SET) return 1; else return 0;
}

void kbd_init(void)
{
    InitKeyHard();      /* 初始化按键硬件 */
    InitKeyVar();       /* 初始化按键变量 */
}

/*
*********************************************************************************************************
*   函 数 名: PutKey
*   功能说明: 将1个键值压入按键FIFO缓冲区。可用于模拟一个按键。
*   形    参: _KeyCode : 按键代码
*   返 回 值: 无
*********************************************************************************************************
*/
void PutKey(uint8_t _KeyCode)
{
    s_tKey.Buf[s_tKey.Write] = _KeyCode;

    if (++s_tKey.Write >= KEY_FIFO_SIZE)
    {
        s_tKey.Write = 0;
    }
}

/*
*********************************************************************************************************
*   函 数 名: GetKey
*   功能说明: 从按键FIFO缓冲区读取一个键值。使用第1个读指针。
*   形    参: 无
*   返 回 值: 按键代码
*********************************************************************************************************
*/
KEY_ENUM kbd_GetKey(void)
{
    uint8_t ret;

    if (s_tKey.Read == s_tKey.Write)
    {
        return KEY_NONE;
    }
    else
    {
        ret = s_tKey.Buf[s_tKey.Read];

        if (++s_tKey.Read >= KEY_FIFO_SIZE)
        {
            s_tKey.Read = 0;
        }
        DBG_DEBUG("key:%d", ret);
        return (KEY_ENUM)ret;
    }
}

/*
*********************************************************************************************************
*   函 数 名: GetKey2
*   功能说明: 从按键FIFO缓冲区读取一个键值。使用第2个读指针。
*   形    参: 无
*   返 回 值: 按键代码
*********************************************************************************************************
*/
uint8_t kbd_GetKey2(void)
{
    uint8_t ret;

    if (s_tKey.Read2 == s_tKey.Write)
    {
        return KEY_NONE;
    }
    else
    {
        ret = s_tKey.Buf[s_tKey.Read2];

        if (++s_tKey.Read2 >= KEY_FIFO_SIZE)
        {
            s_tKey.Read2 = 0;
        }
        return ret;
    }
}

/*
*********************************************************************************************************
*   函 数 名: GetKeyState
*   功能说明: 读取按键的状态
*   形    参: _ucKeyID : 按键ID，从0开始
*   返 回 值: 1 表示按下， 0 表示未按下
*********************************************************************************************************
*/
uint8_t GetKeyState(KEY_ENUM _ucKeyID)
{
    return s_tBtn[_ucKeyID].State;
}

/*
*********************************************************************************************************
*   函 数 名: SetKeyParam
*   功能说明: 设置按键参数
*   形    参: _ucKeyID : 按键ID，从0开始
*             _LongTime : 长按事件时间, 单位为10ms
*             _RepeatSpeed : 连发速度, 单位为10ms
*   返 回 值: 无
*********************************************************************************************************
*/
void SetKeyParam(uint8_t _ucKeyID, uint16_t _LongTime, uint8_t  _RepeatSpeed)
{
    s_tBtn[_ucKeyID].LongTime = _LongTime;          /* 长按时间 0 表示不检测长按键事件 */
    s_tBtn[_ucKeyID].RepeatSpeed = _RepeatSpeed;    /* 按键连发的速度，0表示不支持连发 */
    s_tBtn[_ucKeyID].RepeatCount = 0;               /* 连发计数器 */
}

/*
*********************************************************************************************************
*   函 数 名: ClearKey
*   功能说明: 清空按键FIFO缓冲区
*   形    参: 无
*   返 回 值: 无
*********************************************************************************************************
*/
void ClearKey(void)
{
    s_tKey.Read = s_tKey.Write;
}

/*
*********************************************************************************************************
*   函 数 名: InitKeyHard
*   功能说明: 配置按键对应的GPIO
*   形    参: 无
*   返 回 值: 无
*********************************************************************************************************
*/
static void InitKeyHard(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOG, ENABLE);

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_InitStructure.GPIO_Pin = KEY_L_Pin;
    GPIO_Init(KEY_L_Port, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = KEY_R_Pin;
    GPIO_Init(KEY_R_Port, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = KEY_U_Pin;
    GPIO_Init(KEY_U_Port, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = KEY_D_Pin;
    GPIO_Init(KEY_D_Port, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = KEY_C_Pin;
    GPIO_Init(KEY_C_Port, &GPIO_InitStructure);
}
/*
*********************************************************************************************************
*   函 数 名: InitKeyVar
*   功能说明: 初始化按键变量
*   形    参: 无
*   返 回 值: 无
*********************************************************************************************************
*/
static void InitKeyVar(void)
{
    uint8_t i;

    /* 对按键FIFO读写指针清零 */
    s_tKey.Read = 0;
    s_tKey.Write = 0;
    s_tKey.Read2 = 0;

    /* 给每个按键结构体成员变量赋一组缺省值 */
    for (i = 0; i < KEY_COUNT; i++)
    {
        s_tBtn[i].LongTime = KEY_LONG_TIME;         /* 长按时间 0 表示不检测长按键事件 */
        s_tBtn[i].Count = KEY_FILTER_TIME / 2;      /* 计数器设置为滤波时间的一半 */
        s_tBtn[i].State = 0;                            /* 按键缺省状态，0为未按下 */
        s_tBtn[i].RepeatSpeed = 0;                      /* 按键连发的速度，0表示不支持连发 */
        s_tBtn[i].RepeatCount = 0;                      /* 连发计数器 */
    }

    /* 判断按键按下的函数 */
    s_tBtn[0].IsKeyDownFunc = IsKeyDown_L;
    s_tBtn[1].IsKeyDownFunc = IsKeyDown_R;
    s_tBtn[2].IsKeyDownFunc = IsKeyDown_U;
    s_tBtn[3].IsKeyDownFunc = IsKeyDown_D;
    s_tBtn[4].IsKeyDownFunc = IsKeyDown_C;

}


/*
*********************************************************************************************************
*   函 数 名: DetectKey
*   功能说明: 检测一个按键。非阻塞状态，必须被周期性的调用。
*   形    参:  按键结构变量指针
*   返 回 值: 无
*********************************************************************************************************
*/
static void DetectKey(uint8_t i)
{
    KEY_T* pBtn;

    /*
    如果没有初始化按键函数，则报错
    if (s_tBtn[i].IsKeyDownFunc == 0)
    {
    printf("Fault : DetectButton(), s_tBtn[i].IsKeyDownFunc undefine");
    }
    */

    pBtn = &s_tBtn[i];
    if (pBtn->IsKeyDownFunc())
    {
        if (pBtn->Count < KEY_FILTER_TIME)
        {
            pBtn->Count = KEY_FILTER_TIME;
        }
        else if (pBtn->Count < 2 * KEY_FILTER_TIME)
        {
            pBtn->Count++;
        }
        else
        {
            if (pBtn->State == 0)
            {
                pBtn->State = 1;

                /* 发送按钮按下的消息 */
                PutKey((uint8_t)(3 * i + 1));
            }

            if (pBtn->LongTime > 0)
            {
                if (pBtn->LongCount < pBtn->LongTime)
                {
                    /* 发送按钮持续按下的消息 */
                    if (++pBtn->LongCount == pBtn->LongTime)
                    {
                        /* 键值放入按键FIFO */
                        PutKey((uint8_t)(3 * i + 3));
                    }
                }
                else
                {
                    if (pBtn->RepeatSpeed > 0)
                    {
                        if (++pBtn->RepeatCount >= pBtn->RepeatSpeed)
                        {
                            pBtn->RepeatCount = 0;
                            /* 长按键后，每隔10ms发送1个按键 */
                            PutKey((uint8_t)(3 * i + 1));
                        }
                    }
                }
            }
        }
    }
    else
    {
        if (pBtn->Count > KEY_FILTER_TIME)
        {
            pBtn->Count = KEY_FILTER_TIME;
        }
        else if (pBtn->Count != 0)
        {
            pBtn->Count--;
        }
        else
        {
            if (pBtn->State == 1)
            {
                pBtn->State = 0;

                /* 发送按钮弹起的消息 */
                PutKey((uint8_t)(3 * i + 2));
            }
        }

        pBtn->LongCount = 0;
        pBtn->RepeatCount = 0;
    }
}

/*
*********************************************************************************************************
*   函 数 名: KeyScan
*   功能说明: 扫描所有按键。非阻塞，被systick中断周期性的调用
*   形    参: 无
*   返 回 值: 无
*********************************************************************************************************
*/
void KeyScan(void)
{
    uint8_t i;

    for (i = 0; i < KEY_COUNT; i++)
    {
        DetectKey(i);
    }
}


//KEYn kbd_scan(uint8_t wait, uint8_t mode)
//{
//    uint8_t t = 1;
//    do
//    {
//        if (GPIO_ReadInputDataBit(KEY_L_Port, KEY_L_Pin))
//        {
//            delayMs(t);
//            if (mode == 1)
//            {
//                return KEY_L;
//            }
//            while (!GPIO_ReadInputDataBit(KEY_L_Port, KEY_L_Pin))
//                return KEY_L;
//        }
//        else if (GPIO_ReadInputDataBit(KEY_R_Port, KEY_R_Pin))
//        {
//            delayMs(t);
//            if (mode == 1)
//            {
//                return KEY_R;
//            }
//            while (!GPIO_ReadInputDataBit(KEY_R_Port, KEY_R_Pin))
//                return KEY_R;
//        }
//        else if (GPIO_ReadInputDataBit(KEY_C_Port, KEY_C_Pin))
//        {
//            delayMs(t);
//            while (!GPIO_ReadInputDataBit(KEY_C_Port, KEY_C_Pin))
//                return KEY_C;
//        }
//        else if (GPIO_ReadInputDataBit(KEY_U_Port, KEY_U_Pin))
//        {
//            delayMs(t);
//            while (!GPIO_ReadInputDataBit(KEY_U_Port, KEY_U_Pin))
//                return KEY_U;
//        }
//        else if (GPIO_ReadInputDataBit(KEY_D_Port, KEY_D_Pin))
//        {
//            delayMs(t);
//            while (!GPIO_ReadInputDataBit(KEY_D_Port, KEY_D_Pin))
//                return KEY_D;
//        }
//        if (!wait)
//        {
//            return KEY_N;
//        }
//        PrintKeyStatu();
//    } while (wait);
//    return KEY_N;
//}

void PrintKeyStatu(void)
{
    DBG_DEBUG("Key:KEY_L-Status:%d   ", GPIO_ReadInputDataBit(KEY_L_Port, KEY_L_Pin));
    DBG_DEBUG("Key:KEY_R-Status:%d   ", GPIO_ReadInputDataBit(KEY_R_Port, KEY_R_Pin));
    DBG_DEBUG("Key:KEY_U-Status:%d   ", GPIO_ReadInputDataBit(KEY_U_Port, KEY_U_Pin));
    DBG_DEBUG("Key:KEY_D-Status:%d   ", GPIO_ReadInputDataBit(KEY_D_Port, KEY_D_Pin));
    DBG_DEBUG("Key:KEY_C-Status:%d   ", GPIO_ReadInputDataBit(KEY_C_Port, KEY_C_Pin));
}




